﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using TianShu.TenantManagement.Dal.Abstracts.Entities;
using TianShu.TenantManagement.Dal.Abstracts.Manager;
using Volo.Abp;

namespace TianShu.TenantManagement.Dal.Manager
{
    public class TenantManager : DomainService, ITenantManager
    {
        protected IRepository<TenantEntity, Guid> TenantRepository { get; }
        protected IRepository<TenantConnectionStringEntity, Guid> TenantConnectionStringRepository { get; }

        public TenantManager(IRepository<TenantEntity, Guid> tenantRepository, IRepository<TenantConnectionStringEntity, Guid> tenantConnectionStringRepository)
        {
            TenantRepository = tenantRepository;
            TenantConnectionStringRepository = tenantConnectionStringRepository;
        }

        public virtual async Task<TenantEntity> CreateAsync(string code, string name)
        {
            Check.NotNull(code, nameof(code));
            Check.NotNull(name, nameof(name));

            await ValidateNameAsync(name);
            return new TenantEntity(GuidGenerator.Create(),code, name);
        }

        public virtual async Task ChangeNameAsync(TenantEntity tenant, string name)
        {
            Check.NotNull(tenant, nameof(tenant));
            Check.NotNull(name, nameof(name));

            await ValidateNameAsync(name, tenant.Id);
            tenant.SetName(name);
        }

        protected virtual async Task ValidateNameAsync(string name, Guid? expectedId = null)
        {
            var tenant = await TenantRepository.FindAsync(e => e.Name == name);
            if (tenant != null && tenant.Id != expectedId)
            {
                throw new UserFriendlyException("Duplicate tenancy name: " + name); //TODO: A domain exception would be better..?
            }
        }


        public virtual async Task<TenantEntity> FindAndConnectionStringAsync(Expression<Func<TenantEntity, bool>> expression)
        {
            var tenant = await TenantRepository.FindAsync(expression);
            if (tenant == null)
            {
                return tenant;
            }
            tenant.ConnectionStrings = (await TenantConnectionStringRepository.GetListAsync(e => e.TenantId == tenant.Id)).ToList();
            return tenant;

        }

        public virtual async Task<TenantEntity> UpdateAndConnectionStringAsync(TenantEntity entity)
        {
            await TenantRepository.UpdateAsync(entity);

            await TenantConnectionStringRepository.DeleteAsync(e => e.TenantId == entity.Id);

            await TenantConnectionStringRepository.InsertManyAsync(entity.ConnectionStrings);
            return entity;
        }
    }
}
